package edu.simplemqom.protocol;

import java.io.IOException;
import java.io.InputStream;
import java.net.ProtocolException;

/**
 * 
 */
public class SMQOMProtocol {

	public static final SMQOMPackage readPackageFromStream(InputStream in) throws ProtocolException, IOException {
		int sessionId, dataSize, bytesRead;
		byte commandId;
		byte[] buffer;
		byte[] data = null;
		SMQOMPackage pkg;
		
		buffer = new byte[1];
		
		while(in.read(buffer, 0, 1) != 1) {
		}
		
		if (buffer[0] != SMQOMCommandId.SMQOM_MAGIC) {
			throw new ProtocolException("This is not SMQOM package");
		} 
		
		buffer = new byte[4];
		bytesRead = 0;
		while(bytesRead < 4) {
			bytesRead += in.read(buffer, bytesRead, 4 - bytesRead);
		}
		sessionId = SMQOMProtocol.byteArrayToInt(buffer);
		
		buffer = new byte[4];
		bytesRead = 0;
		while(bytesRead < 4) {
			bytesRead += in.read(buffer, bytesRead, 4 - bytesRead);
		}
		
		dataSize = SMQOMProtocol.byteArrayToInt(buffer);
		
		buffer = new byte[1];
		while(in.read(buffer, 0, 1) != 1) {
		}
		commandId = buffer[0];
		
		if(dataSize > 0) {
			buffer = new byte[dataSize];
			bytesRead = 0;
			while(bytesRead < dataSize) {
				bytesRead += in.read(buffer, bytesRead, dataSize - bytesRead);
			}
			data = buffer;
		}
		
		buffer = new byte[1];
		while(in.read(buffer, 0, 1) != 1) {
			
		}
		if (buffer[0] != SMQOMCommandId.SMQOM_MAGIC) {
			throw new ProtocolException("Bad end of SMQOM package");
		} 
		
		pkg = new SMQOMPackage(commandId, sessionId, data);
		
		return pkg;
	}
	
	public static final boolean isAcknowledgement(SMQOMPackage pack) throws ProtocolException {
		if (pack.getCommandId() == SMQOMCommandId.ACK) {
			if (pack.getDataSize() == 0) {
				return true;
			} else {
				throw new ProtocolException("Bad ACK package. Received ACK package but it contains data");
			}
		} else {
			return false;
		}
	}

	public static final int byteArrayToInt(byte [] b) {
	    return (b[0] << 24)
	            + ((b[1] & 0xFF) << 16)
	            + ((b[2] & 0xFF) << 8)
	            + (b[3] & 0xFF);
	}

	public static final byte[] intToByteArray(int value) {
	    return new byte[] {
	            (byte)(value >>> 24),
	            (byte)(value >>> 16),
	            (byte)(value >>> 8),
	            (byte)value};
	}

}
